]> dgit.raspbian.org Git - gnome-shell.git/commitdiff
popupMenu: Queue relayout on popup menu parent when opening
authorJonas Ådahl <jadahl@gmail.com>
Fri, 5 Sep 2025 13:53:52 +0000 (15:53 +0200)
committerFlorian Müllner <fmuellner@gnome.org>
Sat, 13 Sep 2025 17:03:25 +0000 (19:03 +0200)
The position of the menu depends on the position of the "source actor",
but the source actor is not a parent of the menu, but typically a
sibling.

Since we depend on the source actor position for placing the popup menu,
it's important that the source actor gets allocated before we allocate.
Currently the only way to ensure that the source actor is allocated
before the popup menu is by handling the layout via the parent actor, as
the order of the allocations done when queuing shallow relayouts is
currently undefined. As of d94638acae ("clutter/actor: Make child
position changes a noop when possible") in mutter,
Clutter.Actor.set_child_above_sibling() has a fast path when the
position doesn't change, which means the parent was did not get its
relayout queued. This caused the popup menu to end up being allocated
before the source actor, thus using an out of date source actor
allocation to base its position calculation on.

To fix this, queue a relayout on the parent actor unconditionally, after
inserting it into the parent actor, to let us be able to rely on the
source actor having been allocated before the popup menu itself getting
allocated.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/4253
Part-of: <https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/3863>
(cherry picked from commit ca198804598daf595d56600b76b0a0fd088252ee)

js/ui/popupMenu.js

index a068ced5ef94a1402ccc07a4c6355158db5d6696..76df95dae53290201f53290097cdd5025cd63301 100644 (file)
@@ -1119,6 +1119,13 @@ export class PopupMenu extends PopupMenuBase {
 
         this.actor.get_parent().set_child_above_sibling(this.actor, null);
 
+        /* The position calculation expects the source actor allocation to be
+         * up to date, so queue relayout on parent to ensure it gets allocated
+         * first.
+         */
+        if (!this.sourceActor?.has_allocation())
+            this.sourceActor?.get_parent().queue_relayout();
+
         this.emit('open-state-changed', true);
     }